package com.yudean.esb.service.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yudean.esb.common.Constants;
import com.yudean.esb.dao.esb.FwsDataDao;
import com.yudean.esb.domain.erp.ErpControl;
import com.yudean.esb.domain.erp.ErpFwsContract;
import com.yudean.esb.domain.erp.ErpFwsPayments;
import com.yudean.esb.security.SecurtiyChecker;
import org.dozer.DozerBeanMapper;
import org.dozer.loader.api.BeanMappingBuilder;
import org.dozer.loader.api.FieldDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import static org.dozer.loader.api.FieldsMappingOptions.hintA;
import static org.dozer.loader.api.FieldsMappingOptions.hintB;

/**
 * <pre>
 * 法务系统推送数据的处理工具接口
 * </pre>
 *
 * @author Lei Duan<duanlei#gdyd.com>
 * @version 1.0.0
 * @since 0.0.2
 */
@Service("fwsDataHander")
@Scope("prototype")
public class FWSDataHandler {
    private final static Logger LOGGER = LoggerFactory.getLogger(FWSDataHandler.class);

    @Resource
    private FwsDataDao erpfwsdataDao;

    @Resource
    private SecurtiyChecker securtiyChecker;

    /**
     * 处理法务系统发送过来的控制表信息
     *
     * @param controlData 控制表信息
     * @return JSON data
     */
    public String handleControlData(String controlData, String token) {
        if (!isAccessable(token)) {
            return returnMsg("erp_ids_control", token, "",
                    Constants.CODE_AUTH_ERROR, Constants.CODE_AUTH_ERROR_MSG);
        }
        LOGGER.info("controlData={}", controlData);

        JSONArray jsonArray = JSONArray.parseArray(controlData);
        if (jsonArray == null || jsonArray.size() < 1)
            return returnMsg("erp_ids_control", "", "", Constants.CODE_CLIENT_ERROR, "发送无数据内容!");

        //数据转换的过程，以及验证数据的格式是否正确
        List<ErpControl> dataList = new ArrayList<ErpControl>();
        LOGGER.info("convert json to Java Bean");
        for (Object obj : jsonArray) {
            JSONObject json = (JSONObject) obj;
            ErpControl item = convert2Control(json);
            if (item == null) {
                return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR_MSG, "无法映射数据，检查数据提交接口是否正确");
            }
            if (item.hasViolations()) {
                return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR_MSG, "发送数据不合法，检查数据格式");
            }
            dataList.add(item);
        }
        //这是对应的一条数据，如果是多条的话，需要循环
        //TODO 需要适应将来传送多条数据的情况
        ErpControl control = dataList.get(0);
        //判断是否已经存在了同样的控制表信息，如果存在表示已有数据存入，需要进行转存操作
        boolean hasTransferedData = erpfwsdataDao.isControlExist(control.getControlId() + "");
        erpfwsdataDao.saveControl(control);
        if (hasTransferedData) {
            LOGGER.info("need to transfer to ERP");
            return erpfwsdataDao.tryTransferControl(control.getControlId() + "") ? returnOk() : returnErr();
        } else {
            return returnOk();
        }
    }

    /**
     * 将信息转换成可以处理的对象
     *
     * @param json 传入信息
     * @return ErpControl
     */
    private ErpControl convert2Control(JSONObject json) {
        try {
            return controlMapper.map(json, ErpControl.class);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * 处理法务系统传送过来的的合同数据
     *
     * @param contractData 合同信息数据
     * @return JSON data
     */
    public String handleContractData(String contractData, String token) {
        if (!isAccessable(token)) {
            return returnMsg("erp_ids_control", token, "",
                    Constants.CODE_AUTH_ERROR, Constants.CODE_AUTH_ERROR_MSG);
        }
        LOGGER.info("contractData={}", contractData);

        //数据转换的过程，以及验证数据的格式是否正确
        List<ErpFwsContract> dataList = new ArrayList<ErpFwsContract>();
        try {
            JSONArray jsonArray = JSON.parseArray(contractData);

            if (jsonArray == null || jsonArray.size() < 1)
                return returnMsg("erp_ids_contract", "", "", Constants.CODE_CLIENT_ERROR, "发送无数据内容!");
            LOGGER.info("transform to Java Bean");
            for (Object obj : jsonArray) {
                JSONObject json = (JSONObject) obj;
                ErpFwsContract item = convert2Contract(json);
                if (item == null) {
                    return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR, "无法映射数据，检查数据提交接口是否正确");
                }
                if (item.hasViolations()) {
                    return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR, "发送数据不合法，检查数据格式");
                }
                dataList.add(item);
            }
        } catch (Exception ex) {
            LOGGER.error("handleContractData:err={}", ex.getMessage());
            return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR, "发送数据不合法，检查数据格式");
        }


        //这是对应的一条数据，如果是多条的话，需要循环
        //TODO 需要适应将来传送多条数据的情况
        ErpFwsContract contract = dataList.get(0);
        LOGGER.info("handle data stage");
        //判断是否已经存在了同样的控制表信息，如果存在表示已有数据存入，需要进行转存操作
        boolean hasTransferedData = erpfwsdataDao.isControlExist(contract.getControlId() + "");
        erpfwsdataDao.saveContract(contract);
        if (hasTransferedData) {
            LOGGER.info("need to transfer data to ERP");
            return erpfwsdataDao.tryTransferControl(contract.getControlId() + "") ? returnOk() : returnErr();
        } else {
            return returnOk();
        }
    }

    /**
     * 将推送数据转换成法务系统的合同对象
     *
     * @param jsonObject 合同数据
     * @return 合同对象
     */
    private ErpFwsContract convert2Contract(JSONObject jsonObject) {
        try {
            return contractMapper.map(jsonObject, ErpFwsContract.class);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * 处理法务系统推送过来的付款信息数据
     *
     * @param paymentsData 付款数据
     * @return JSON data
     */
    public String handlePaymentsData(String paymentsData, String token) {
        if (!isAccessable(token)) {
            return returnMsg("erp_ids_control", token, "",
                    Constants.CODE_AUTH_ERROR, Constants.CODE_AUTH_ERROR_MSG);
        }
        LOGGER.info("paymentsData={}", paymentsData);

        JSONArray jsonArray = JSON.parseArray(paymentsData);
        if (jsonArray == null || jsonArray.size() < 1)
            return returnMsg("erp_ids_payments", "", "", Constants.CODE_CLIENT_ERROR, "发送无数据内容!");
        //数据转换的过程，以及验证数据的格式是否正确
        List<ErpFwsPayments> dataList = new ArrayList<ErpFwsPayments>();
        LOGGER.info("convert json to Java Bean");
        for (Object obj : jsonArray) {
            JSONObject json = (JSONObject) obj;
            ErpFwsPayments item = convert2Payments(json);
            if (item == null) {
                return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR_MSG, "无法映射数据，检查数据提交接口是否正确");
            }
            if (item.hasViolations()) {
                return returnMsg("erp_ids_control", "", "", Constants.CODE_ERROR_MSG, "发送数据不合法，检查数据格式");
            }
            dataList.add(item);
        }

        //这是对应的一条数据，如果是多条的话，需要循环
        //TODO 需要适应将来传送多条数据的情况
        ErpFwsPayments payments = dataList.get(0);
        LOGGER.info("handle data stage");
        //判断是否已经存在了同样的控制表信息，如果存在表示已有数据存入，需要进行转存操作
        boolean hasTransferedData = erpfwsdataDao.isControlExist(payments.getControlId() + "");
        erpfwsdataDao.savePayments(payments);
        if (hasTransferedData) {
            LOGGER.info("need to transfer to ERP");
            return erpfwsdataDao.tryTransferControl(payments.getControlId() + "") ? returnOk() : returnErr();
        } else {
            return returnOk();
        }
    }

    /**
     * 转换成付款的对象数据类型
     *
     * @param jsonObject JSON
     * @return 付款信息
     */
    private ErpFwsPayments convert2Payments(JSONObject jsonObject) {
        try {
            return paymentsMapper.map(jsonObject, ErpFwsPayments.class);
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 判断是否可以访问接口，这里只对法务系统做验证
     *
     * @param token 密钥
     * @return TRUE TO ACCESS
     */
    private boolean isAccessable(String token) {
        boolean isValid = false;
        // 验证token
        String[] userInfo = securtiyChecker.getUserInfo(token);
        if (userInfo != null && ("ZSR_EAM".equals(userInfo[0])
                || "HHW".equals(userInfo[0])
                || "FWS".equals(userInfo[0])
                || "ZHP_EAM".equals(userInfo[0])
                || "HDR_MIS".equals(userInfo[0]))) {
            isValid = true;
        }
        return isValid;
    }

    /**
     * 返回成功的消息
     *
     * @return 成功
     */
    private static String returnOk() {
        return returnMsg("", "", "", Constants.CODE_SUCCESS, Constants.CODE_SUCCESS_MSG);
    }

    /**
     * 返回写入失败的信息
     *
     * @return ERROR
     */
    private static String returnErr() {
        return returnMsg("", "", "", Constants.CODE_DB_ERROR, "写入ERP失败，信息有误！");
    }

    private static String returnMsg(String serviceID, String token,
                                    String transactionID, String result, String msg) {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><service>")
                .append("<serviceID>").append(serviceID).append("</serviceID>")
                .append("<token>").append(token).append("</token>")
                .append("<transactionID>").append(transactionID)
                .append("</transactionID>").append("<result>").append(result)
                .append("</result><msg>").append(msg)
                .append("</msg></service>");
        return sb.toString();
    }

    //控制表的映射关系:注意映射中时间已经被正确处理
    //其中，日期Str为多余处理的情况
    private static BeanMappingBuilder controlMapping = new BeanMappingBuilder() {
        @Override
        protected void configure() {
            mapping(JSONObject.class, ErpControl.class)
                    .fields(getMapperDefine("controlId"), "controlId", hintA(String.class), hintB(Long.class))
                    .fields(getMapperDefine("sourceCode"), "sourceCode")
                    .fields(getMapperDefine("sourceCompCode"), "sourceCompCode")
                    .fields(getMapperDefine("targetCode"), "targetCode")
                    .fields(getMapperDefine("targetCompCode"), "targetCompCode")
                    .fields(getMapperDefine("targetModel"), "targetModel")
                    .fields(getMapperDefine("processStatus"), "processStatus")
                    .fields(getMapperDefine("receiveStatus"), "receiveStatus")
                    .fields(getMapperDefine("recordCount"), "recordCount", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("errorMessage"), "errorMessage")
                    .fields(getMapperDefine("creationDate"), "creationDateStr")
                    .fields(getMapperDefine("createdBy"), "createdBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("lastUpdateDate"), "lastUpdateDateStr")
                    .fields(getMapperDefine("lastUpdatedBy"), "lastUpdatedBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("attribute1"), "attribute1")
                    .fields(getMapperDefine("attribute2"), "attribute2")
                    .fields(getMapperDefine("attribute3"), "attribute3")
                    .fields(getMapperDefine("attribute4"), "attribute4")
                    .fields(getMapperDefine("attribute5"), "attribute5")
                    .fields(getMapperDefine("attribute6"), "attribute6")
                    .fields(getMapperDefine("attribute7"), "attribute7")
                    .fields(getMapperDefine("attribute8"), "attribute8")
                    .fields(getMapperDefine("attribute9"), "attribute9")
                    .fields(getMapperDefine("attribute10"), "attribute10")
            ;
        }
    };

    // 合同信息的映射关系，存在多余处理
    public static BeanMappingBuilder contractMapping = new BeanMappingBuilder() {
        @Override
        protected void configure() {
            mapping(JSONObject.class, ErpFwsContract.class)
                    .fields(getMapperDefine("controlId"), "controlId", hintA(String.class), hintB(Long.class))
                    .fields(getMapperDefine("compCode"), "compCode")
                    .fields(getMapperDefine("contractCode"), "contractCode")
                    .fields(getMapperDefine("contractName"), "contractName")
                    .fields(getMapperDefine("vendorCode"), "vendorCode")
                    .fields(getMapperDefine("vendorName"), "vendorName")
                    .fields(getMapperDefine("contractType"), "contractType")
                    .fields(getMapperDefine("contractDesc"), "contractDesc")
                    .fields(getMapperDefine("originalAmount"), "originalAmount", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("paymentTerm"), "paymentTerm")
                    .fields(getMapperDefine("contractAmount"), "contractAmount", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("creationDate"), "creationDateStr")
                    .fields(getMapperDefine("createdBy"), "createdBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("lastUpdateDate"), "lastUpdateDateStr")
                    .fields(getMapperDefine("lastUpdatedBy"), "lastUpdatedBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("attribute1"), "attribute1")
                    .fields(getMapperDefine("attribute2"), "attribute2")
                    .fields(getMapperDefine("attribute3"), "attribute3")
                    .fields(getMapperDefine("attribute4"), "attribute4")
                    .fields(getMapperDefine("attribute5"), "attribute5")
                    .fields(getMapperDefine("attribute6"), "attribute6")
                    .fields(getMapperDefine("attribute7"), "attribute7")
                    .fields(getMapperDefine("attribute8"), "attribute8")
                    .fields(getMapperDefine("attribute9"), "attribute9")
                    .fields(getMapperDefine("attribute10"), "attribute10")
                    .fields(getMapperDefine("vendorAmount"), "vendorAmount")
                    .fields(getMapperDefine("initPaid"), "initPaid")
                    .exclude("vendorList")
                    .exclude("contractVendors")
            ;
        }
    };


    //付款信息的映射关系，存在多余处理
    public static BeanMappingBuilder paymentsMapping = new BeanMappingBuilder() {
        @Override
        protected void configure() {
            mapping(JSONObject.class, ErpFwsPayments.class)
                    .fields(getMapperDefine("controlId"), "controlId", hintA(String.class), hintB(Long.class))
                    .fields(getMapperDefine("paymentIntId"), "paymentIntId", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("compCode"), "compCode")
                    .fields(getMapperDefine("contractCode"), "contractCode")
                    .fields(getMapperDefine("paymentPhase"), "paymentPhase", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("paymentType"), "paymentType")
                    .fields(getMapperDefine("paymentApprovedDate"), "paymentApprovedDateStr")
                    .fields(getMapperDefine("amountPayable"), "amountPayable", hintB(BigDecimal.class), hintA(String.class))
                    .fields(getMapperDefine("amountInvoiced"), "amountInvoiced", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("amountTax"), "amountTax", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("amountDeposit"), "amountDeposit", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("creationDate"), "creationDateStr")
                    .fields(getMapperDefine("createdBy"), "createdBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("lastUpdateDate"), "lastUpdateDateStr")
                    .fields(getMapperDefine("lastUpdatedBy"), "lastUpdatedBy", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("erpPaidDate"), "erpPaidDateStr")
                    .fields(getMapperDefine("erpPaidAmount"), "erpPaidAmount", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("totalReceiptAmount"), "totalReceiptAmount", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("faFlag"), "faFlag")
                    .fields(getMapperDefine("vendorCode"), "vendorCode")
                    .fields(getMapperDefine("vendorName"), "vendorName")
                    .fields(getMapperDefine("historicalContract"), "historicalContract")
                    .fields(getMapperDefine("docNumber"), "docNumber", hintA(String.class), hintB(Integer.class))
                    .fields(getMapperDefine("totalReceiptAmount"), "totalReceiptAmount", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("vendorTotalPaidAmt"), "vendorTotalPaidAmt", hintA(String.class), hintB(BigDecimal.class))
                    .fields(getMapperDefine("vendorTotalReceiptAmt"), "vendorTotalReceiptAmt", hintA(String.class), hintB(BigDecimal.class))

                    .fields(getMapperDefine("attribute1"), "attribute1")
                    .fields(getMapperDefine("attribute2"), "attribute2")
                    .fields(getMapperDefine("attribute3"), "attribute3")
                    .fields(getMapperDefine("attribute4"), "attribute4")
                    .fields(getMapperDefine("attribute5"), "attribute5")
                    .fields(getMapperDefine("attribute6"), "attribute6")
                    .fields(getMapperDefine("attribute7"), "attribute7")
                    .fields(getMapperDefine("attribute8"), "attribute8")
                    .fields(getMapperDefine("attribute9"), "attribute9")
                    .fields(getMapperDefine("attribute10"), "attribute10")
            ;
        }
    };

    //映射工作组
    private static DozerBeanMapper controlMapper = null;
    private static DozerBeanMapper contractMapper = null;
    private static DozerBeanMapper paymentsMapper = null;

    //初始化好了。
    static {
        controlMapper = new DozerBeanMapper();
        controlMapper.addMapping(controlMapping);

        contractMapper = new DozerBeanMapper();
        contractMapper.addMapping(contractMapping);

        paymentsMapper = new DozerBeanMapper();
        paymentsMapper.addMapping(paymentsMapping);
    }

    /**
     * 获得Map的映射定义
     *
     * @param key 键值
     * @return 映射定义
     */
    private static FieldDefinition getMapperDefine(String key) {
        return new FieldDefinition("this").mapKey(key);
    }
}
